"""BLE Template Management Service.

Provides GATT characteristics for template management operations including
template CRUD, validation, import/export, and application control.
"""

import asyncio
import json
import logging
import struct
import time
import uuid
from typing import Dict, List, Optional, Callable, Any, Union
from enum import Enum

from ...config.template_manager import (
    TemplateManager, ConfigTemplate, TemplateCategory, TemplateStatus,
    ValidationRule
)
from ...config.template_applicator import (
    TemplateApplicator, ApplicationStatus, ConflictResolution
)

logger = logging.getLogger(__name__)


# Template Service UUID: FF60
TEMPLATE_SERVICE_UUID = "0000FF60-0000-1000-8000-00805F9B34FB"
TEMPLATE_CONTROL_UUID = "0000FF61-0000-1000-8000-00805F9B34FB"    # Write
TEMPLATE_LIST_UUID = "0000FF62-0000-1000-8000-00805F9B34FB"       # Read
TEMPLATE_DATA_UUID = "0000FF63-0000-1000-8000-00805F9B34FB"       # Read, Write
TEMPLATE_STATUS_UUID = "0000FF64-0000-1000-8000-00805F9B34FB"     # Read, Notify


class TemplateCommand(Enum):
    """Template management control commands."""
    CREATE_TEMPLATE = 0x01          # Create new template
    UPDATE_TEMPLATE = 0x02          # Update existing template
    DELETE_TEMPLATE = 0x03          # Delete template
    APPLY_TEMPLATE = 0x04           # Apply template to devices
    EXPORT_TEMPLATE = 0x05          # Export template
    IMPORT_TEMPLATE = 0x06          # Import template
    VALIDATE_TEMPLATE = 0x07        # Validate template
    CLONE_TEMPLATE = 0x08           # Clone existing template
    SET_TEMPLATE_STATUS = 0x09      # Change template status
    GET_TEMPLATE_DETAILS = 0x0A     # Get detailed template info


class TemplateDataOperation(Enum):
    """Template data transfer operations."""
    UPLOAD_START = 0x01             # Start template upload
    UPLOAD_CHUNK = 0x02             # Upload data chunk
    UPLOAD_END = 0x03               # End template upload
    DOWNLOAD_START = 0x04           # Start template download
    DOWNLOAD_CHUNK = 0x05           # Download data chunk
    DOWNLOAD_END = 0x06             # End template download


class TemplateOperationStatus(Enum):
    """Template operation status."""
    IDLE = 0x00                     # No active operation
    PROCESSING = 0x01               # Operation in progress
    SUCCESS = 0x02                  # Operation completed successfully
    ERROR = 0x03                    # Operation failed
    VALIDATION_ERROR = 0x04         # Validation failed
    PERMISSION_DENIED = 0x05        # Insufficient permissions
    NOT_FOUND = 0x06               # Template not found
    CONFLICT = 0x07                # Template conflict


class TemplateService:
    """BLE Template Management Service implementation."""
    
    def __init__(self, template_manager: TemplateManager, 
                 template_applicator: TemplateApplicator):
        """Initialize template service.
        
        Args:
            template_manager: Template manager instance
            template_applicator: Template applicator instance
        """
        self.template_manager = template_manager
        self.template_applicator = template_applicator
        
        # Service state
        self.current_operation_id: Optional[str] = None
        self.operation_status = TemplateOperationStatus.IDLE
        self.operation_progress = 0.0
        self.operation_result: Optional[Dict[str, Any]] = None
        self.operation_error: Optional[str] = None
        
        # Data transfer state
        self.upload_session: Optional[Dict[str, Any]] = None
        self.download_session: Optional[Dict[str, Any]] = None
        
        # Notification callback
        self.notify_callback: Optional[Callable[[str, bytes], None]] = None
        
        # Service registration data
        self.service_data = self._create_service_definition()
        
        # Status notification task
        self.status_task: Optional[asyncio.Task] = None
        self.status_notify_interval = 10  # 10 seconds
        
        # MTU and fragmentation
        self.mtu_size = 244  # Conservative BLE MTU
        self.max_chunk_size = self.mtu_size - 20  # Account for headers
        
        logger.info("TemplateService initialized")
    
    def _create_service_definition(self) -> Dict[str, Any]:
        """Create GATT service definition."""
        return {
            "uuid": TEMPLATE_SERVICE_UUID,
            "primary": True,
            "characteristics": [
                {
                    "uuid": TEMPLATE_CONTROL_UUID,
                    "flags": ["write"],
                    "value": bytearray(512),  # Command data
                    "descriptors": []
                },
                {
                    "uuid": TEMPLATE_LIST_UUID,
                    "flags": ["read"],
                    "value": bytearray(2048),  # Template list data
                    "descriptors": []
                },
                {
                    "uuid": TEMPLATE_DATA_UUID,
                    "flags": ["read", "write"],
                    "value": bytearray(512),  # Template data transfer
                    "descriptors": []
                },
                {
                    "uuid": TEMPLATE_STATUS_UUID,
                    "flags": ["read", "notify"],
                    "value": bytearray(64),   # Status information
                    "descriptors": [
                        {
                            "uuid": "00002902-0000-1000-8000-00805F9B34FB",  # CCC
                            "flags": ["read", "write"],
                            "value": bytearray([0x00, 0x00])
                        }
                    ]
                }
            ]
        }
    
    async def start(self):
        """Start template service."""
        # Start periodic status notifications
        self.status_task = asyncio.create_task(self._status_notification_loop())
        logger.info("TemplateService started")
    
    async def stop(self):
        """Stop template service."""
        if self.status_task:
            self.status_task.cancel()
            try:
                await self.status_task
            except asyncio.CancelledError:
                pass
        
        # Cancel any active operations
        if self.current_operation_id:
            await self._cancel_current_operation("Service stopped")
        
        logger.info("TemplateService stopped")
    
    # GATT Characteristic Handlers
    
    async def handle_write_template_control(self, value: bytes) -> bool:
        """Handle write to TEMPLATE_CONTROL characteristic."""
        try:
            if not value or len(value) < 1:
                return False
            
            command = TemplateCommand(value[0])
            params = value[1:] if len(value) > 1 else b''
            
            # Start new operation
            operation_id = str(uuid.uuid4())
            self.current_operation_id = operation_id
            self.operation_status = TemplateOperationStatus.PROCESSING
            self.operation_progress = 0.0
            self.operation_result = None
            self.operation_error = None
            
            # Handle command asynchronously
            asyncio.create_task(self._handle_template_command(command, params, operation_id))
            
            return True
            
        except ValueError as e:
            logger.warning(f"Invalid template command: {e}")
            return False
        except Exception as e:
            logger.error(f"Error handling template control: {e}")
            return False
    
    async def handle_read_template_list(self) -> bytes:
        """Handle read from TEMPLATE_LIST characteristic."""
        try:
            # Get template list with optional filters
            templates = await self.template_manager.list_templates()
            
            # Format for BLE transmission
            template_list = []
            for template in templates[:20]:  # Limit to 20 templates
                template_data = {
                    "id": template.template_id,
                    "name": template.name,
                    "category": template.category.value,
                    "version": template.version,
                    "status": template.status.value,
                    "usage_count": template.usage_count,
                    "success_rate": template.success_rate
                }
                template_list.append(template_data)
            
            response_data = {
                "operation": "list_templates",
                "count": len(template_list),
                "templates": template_list,
                "total_available": len(templates)
            }
            
            return json.dumps(response_data).encode('utf-8')[:2048]
            
        except Exception as e:
            logger.error(f"Error reading template list: {e}")
            return json.dumps({"error": "Failed to read template list"}).encode('utf-8')
    
    async def handle_write_template_data(self, value: bytes) -> bool:
        """Handle write to TEMPLATE_DATA characteristic."""
        try:
            if not value or len(value) < 1:
                return False
            
            operation = TemplateDataOperation(value[0])
            data = value[1:]
            
            if operation == TemplateDataOperation.UPLOAD_START:
                return await self._handle_upload_start(data)
            
            elif operation == TemplateDataOperation.UPLOAD_CHUNK:
                return await self._handle_upload_chunk(data)
            
            elif operation == TemplateDataOperation.UPLOAD_END:
                return await self._handle_upload_end(data)
            
            elif operation == TemplateDataOperation.DOWNLOAD_START:
                return await self._handle_download_start(data)
            
            else:
                logger.warning(f"Unknown data operation: {operation}")
                return False
                
        except ValueError as e:
            logger.warning(f"Invalid data operation: {e}")
            return False
        except Exception as e:
            logger.error(f"Error handling template data: {e}")
            return False
    
    async def handle_read_template_data(self) -> bytes:
        """Handle read from TEMPLATE_DATA characteristic."""
        try:
            if not self.download_session:
                return json.dumps({"error": "No active download"}).encode('utf-8')
            
            # Get next chunk
            chunk_data = await self._get_download_chunk()
            
            if chunk_data:
                # Format chunk with operation header
                chunk_header = struct.pack('>B H', 
                                         TemplateDataOperation.DOWNLOAD_CHUNK.value,
                                         len(chunk_data))
                return chunk_header + chunk_data
            else:
                # Download complete
                end_header = struct.pack('>B H', 
                                       TemplateDataOperation.DOWNLOAD_END.value, 0)
                self.download_session = None
                return end_header
                
        except Exception as e:
            logger.error(f"Error reading template data: {e}")
            return json.dumps({"error": "Download failed"}).encode('utf-8')
    
    async def handle_read_template_status(self) -> bytes:
        """Handle read from TEMPLATE_STATUS characteristic."""
        try:
            # Format status information
            status_data = struct.pack(
                '>16s B B H f',
                (self.current_operation_id or 'idle').encode('utf-8')[:16].ljust(16, b'\x00'),
                self.operation_status.value,
                int(self.operation_progress),
                len(self.operation_error or ''),
                time.time()
            )
            
            return status_data
            
        except Exception as e:
            logger.error(f"Error reading template status: {e}")
            return b'\x00' * 32
    
    # Command Handlers
    
    async def _handle_template_command(self, command: TemplateCommand, 
                                     params: bytes, operation_id: str):
        """Handle template command asynchronously."""
        try:
            if operation_id != self.current_operation_id:
                return  # Operation was cancelled
            
            if command == TemplateCommand.CREATE_TEMPLATE:
                await self._handle_create_template(params)
            
            elif command == TemplateCommand.UPDATE_TEMPLATE:
                await self._handle_update_template(params)
            
            elif command == TemplateCommand.DELETE_TEMPLATE:
                await self._handle_delete_template(params)
            
            elif command == TemplateCommand.APPLY_TEMPLATE:
                await self._handle_apply_template(params)
            
            elif command == TemplateCommand.EXPORT_TEMPLATE:
                await self._handle_export_template(params)
            
            elif command == TemplateCommand.IMPORT_TEMPLATE:
                await self._handle_import_template(params)
            
            elif command == TemplateCommand.VALIDATE_TEMPLATE:
                await self._handle_validate_template(params)
            
            elif command == TemplateCommand.CLONE_TEMPLATE:
                await self._handle_clone_template(params)
            
            elif command == TemplateCommand.SET_TEMPLATE_STATUS:
                await self._handle_set_template_status(params)
            
            elif command == TemplateCommand.GET_TEMPLATE_DETAILS:
                await self._handle_get_template_details(params)
            
            else:
                raise ValueError(f"Unknown template command: {command}")
            
            # Operation completed successfully
            self.operation_status = TemplateOperationStatus.SUCCESS
            self.operation_progress = 100.0
            
        except Exception as e:
            logger.error(f"Template command error: {e}")
            self.operation_status = TemplateOperationStatus.ERROR
            self.operation_error = str(e)
        
        finally:
            # Send status notification
            await self._send_status_notification()
            
            # Clear operation after delay
            await asyncio.sleep(5)
            if self.current_operation_id == operation_id:
                self.current_operation_id = None
                self.operation_status = TemplateOperationStatus.IDLE
    
    async def _handle_create_template(self, params: bytes):
        """Handle create template command."""
        if not params:
            raise ValueError("Missing template parameters")
        
        template_data = json.loads(params.decode('utf-8'))
        
        template_id = await self.template_manager.create_template(
            name=template_data["name"],
            description=template_data.get("description", ""),
            category=TemplateCategory(template_data.get("category", "custom")),
            config_schema=template_data.get("config_schema"),
            default_values=template_data.get("default_values"),
            validation_rules=template_data.get("validation_rules", []),
            author=template_data.get("author", "user")
        )
        
        self.operation_result = {"template_id": template_id}
        logger.info(f"Created template: {template_id}")
    
    async def _handle_update_template(self, params: bytes):
        """Handle update template command."""
        if not params:
            raise ValueError("Missing template parameters")
        
        template_data = json.loads(params.decode('utf-8'))
        template_id = template_data["template_id"]
        
        # Update template fields
        update_data = {k: v for k, v in template_data.items() 
                      if k != "template_id"}
        
        success = await self.template_manager.update_template(template_id, **update_data)
        
        if not success:
            raise ValueError(f"Failed to update template {template_id}")
        
        self.operation_result = {"template_id": template_id}
        logger.info(f"Updated template: {template_id}")
    
    async def _handle_delete_template(self, params: bytes):
        """Handle delete template command."""
        if not params:
            raise ValueError("Missing template ID")
        
        delete_data = json.loads(params.decode('utf-8'))
        template_id = delete_data["template_id"]
        
        success = await self.template_manager.delete_template(template_id)
        
        if not success:
            raise ValueError(f"Failed to delete template {template_id}")
        
        self.operation_result = {"template_id": template_id}
        logger.info(f"Deleted template: {template_id}")
    
    async def _handle_apply_template(self, params: bytes):
        """Handle apply template command."""
        if not params:
            raise ValueError("Missing application parameters")
        
        apply_data = json.loads(params.decode('utf-8'))
        template_id = apply_data["template_id"]
        target_devices = apply_data.get("target_devices", [])
        override_values = apply_data.get("override_values", {})
        options = apply_data.get("options", {})
        
        if not target_devices:
            raise ValueError("No target devices specified")
        
        # Convert device data to DeviceInfo objects (simplified)
        from ...config.batch_manager import DeviceInfo
        from datetime import datetime
        
        device_objects = []
        for device_data in target_devices:
            device = DeviceInfo(
                device_id=device_data["device_id"],
                name=device_data["name"],
                mac_address=device_data["mac_address"],
                signal_strength=device_data.get("signal_strength", -50),
                device_type=device_data.get("device_type", "printer"),
                firmware_version=device_data.get("firmware_version", "1.0.0"),
                last_seen=datetime.now()
            )
            device_objects.append(device)
        
        # Start batch application
        application_id = await self.template_applicator.apply_template_batch(
            template_id, device_objects, override_values, options
        )
        
        self.operation_result = {"application_id": application_id}
        logger.info(f"Started template application: {application_id}")
    
    async def _handle_export_template(self, params: bytes):
        """Handle export template command."""
        if not params:
            raise ValueError("Missing export parameters")
        
        export_data = json.loads(params.decode('utf-8'))
        template_id = export_data["template_id"]
        export_format = export_data.get("format", "json")
        
        # Export template
        exported_data = await self.template_manager.export_template(
            template_id, export_format
        )
        
        # Setup download session
        self.download_session = {
            "data": exported_data,
            "position": 0,
            "total_size": len(exported_data),
            "template_id": template_id,
            "format": export_format
        }
        
        self.operation_result = {
            "template_id": template_id,
            "format": export_format,
            "size": len(exported_data)
        }
        logger.info(f"Prepared template export: {template_id}")
    
    async def _handle_import_template(self, params: bytes):
        """Handle import template command."""
        # Import is handled through upload session
        if not self.upload_session or not self.upload_session.get("completed"):
            raise ValueError("No completed upload session for import")
        
        import_data = json.loads(params.decode('utf-8'))
        import_format = import_data.get("format", "json")
        
        # Import template from uploaded data
        template_data = self.upload_session["data"]
        template_id = await self.template_manager.import_template(
            template_data, import_format
        )
        
        self.operation_result = {"template_id": template_id}
        
        # Clear upload session
        self.upload_session = None
        
        logger.info(f"Imported template: {template_id}")
    
    async def _handle_validate_template(self, params: bytes):
        """Handle validate template command."""
        if not params:
            raise ValueError("Missing validation parameters")
        
        validate_data = json.loads(params.decode('utf-8'))
        template_id = validate_data["template_id"]
        
        # Validate template
        validation_result = await self.template_manager.validate_template(template_id)
        
        self.operation_result = {
            "template_id": template_id,
            "is_valid": validation_result.is_valid,
            "errors": [str(error) for error in validation_result.errors],
            "warnings": [str(warning) for warning in validation_result.warnings]
        }
        
        logger.info(f"Validated template: {template_id}")
    
    async def _handle_clone_template(self, params: bytes):
        """Handle clone template command."""
        if not params:
            raise ValueError("Missing clone parameters")
        
        clone_data = json.loads(params.decode('utf-8'))
        source_template_id = clone_data["source_template_id"]
        new_name = clone_data["new_name"]
        new_description = clone_data.get("new_description", "")
        
        # Clone template
        new_template_id = await self.template_manager.clone_template(
            source_template_id, new_name, new_description
        )
        
        self.operation_result = {
            "source_template_id": source_template_id,
            "new_template_id": new_template_id
        }
        
        logger.info(f"Cloned template {source_template_id} to {new_template_id}")
    
    async def _handle_set_template_status(self, params: bytes):
        """Handle set template status command."""
        if not params:
            raise ValueError("Missing status parameters")
        
        status_data = json.loads(params.decode('utf-8'))
        template_id = status_data["template_id"]
        new_status = TemplateStatus(status_data["status"])
        
        # Update template status
        success = await self.template_manager.update_template(
            template_id, status=new_status
        )
        
        if not success:
            raise ValueError(f"Failed to update template status: {template_id}")
        
        self.operation_result = {
            "template_id": template_id,
            "status": new_status.value
        }
        
        logger.info(f"Updated template status: {template_id} -> {new_status.value}")
    
    async def _handle_get_template_details(self, params: bytes):
        """Handle get template details command."""
        if not params:
            raise ValueError("Missing template ID")
        
        details_data = json.loads(params.decode('utf-8'))
        template_id = details_data["template_id"]
        
        # Get template details
        template = await self.template_manager.get_template(template_id)
        
        if not template:
            raise ValueError(f"Template not found: {template_id}")
        
        # Format detailed template information
        template_details = {
            "template_id": template.template_id,
            "name": template.name,
            "description": template.description,
            "category": template.category.value,
            "version": template.version,
            "status": template.status.value,
            "author": template.author,
            "created_at": template.created_at.isoformat(),
            "updated_at": template.updated_at.isoformat(),
            "usage_count": template.usage_count,
            "success_rate": template.success_rate,
            "device_compatibility": template.device_compatibility,
            "dependencies": template.dependencies,
            "tags": template.tags
        }
        
        self.operation_result = template_details
        logger.info(f"Retrieved template details: {template_id}")
    
    # Data Transfer Handlers
    
    async def _handle_upload_start(self, data: bytes) -> bool:
        """Handle upload start."""
        try:
            upload_info = json.loads(data.decode('utf-8'))
            
            self.upload_session = {
                "total_size": upload_info["size"],
                "received_size": 0,
                "data": bytearray(),
                "checksum": upload_info.get("checksum"),
                "filename": upload_info.get("filename"),
                "format": upload_info.get("format", "json"),
                "completed": False
            }
            
            logger.info(f"Started upload session: {upload_info['size']} bytes")
            return True
            
        except Exception as e:
            logger.error(f"Upload start error: {e}")
            return False
    
    async def _handle_upload_chunk(self, data: bytes) -> bool:
        """Handle upload data chunk."""
        try:
            if not self.upload_session:
                return False
            
            # Add chunk to session data
            self.upload_session["data"].extend(data)
            self.upload_session["received_size"] = len(self.upload_session["data"])
            
            # Update progress
            progress = (self.upload_session["received_size"] / 
                       self.upload_session["total_size"] * 100)
            self.operation_progress = min(progress, 99.0)  # Reserve 100% for completion
            
            return True
            
        except Exception as e:
            logger.error(f"Upload chunk error: {e}")
            return False
    
    async def _handle_upload_end(self, data: bytes) -> bool:
        """Handle upload end."""
        try:
            if not self.upload_session:
                return False
            
            # Verify upload completion
            if (self.upload_session["received_size"] != 
                self.upload_session["total_size"]):
                logger.warning("Upload size mismatch")
                return False
            
            # Verify checksum if provided
            if self.upload_session.get("checksum"):
                import hashlib
                actual_checksum = hashlib.sha256(self.upload_session["data"]).hexdigest()
                if actual_checksum != self.upload_session["checksum"]:
                    logger.error("Upload checksum mismatch")
                    return False
            
            self.upload_session["completed"] = True
            logger.info("Upload completed successfully")
            return True
            
        except Exception as e:
            logger.error(f"Upload end error: {e}")
            return False
    
    async def _handle_download_start(self, data: bytes) -> bool:
        """Handle download start."""
        try:
            if not self.download_session:
                return False
            
            # Reset download position
            self.download_session["position"] = 0
            logger.info("Started download session")
            return True
            
        except Exception as e:
            logger.error(f"Download start error: {e}")
            return False
    
    async def _get_download_chunk(self) -> Optional[bytes]:
        """Get next download chunk."""
        try:
            if not self.download_session:
                return None
            
            position = self.download_session["position"]
            data = self.download_session["data"]
            
            if position >= len(data):
                return None  # Download complete
            
            # Get next chunk
            chunk_size = min(self.max_chunk_size, len(data) - position)
            chunk = data[position:position + chunk_size]
            
            self.download_session["position"] = position + chunk_size
            
            # Update progress
            progress = (self.download_session["position"] / 
                       self.download_session["total_size"] * 100)
            self.operation_progress = progress
            
            return chunk
            
        except Exception as e:
            logger.error(f"Download chunk error: {e}")
            return None
    
    # Notification Methods
    
    async def _send_status_notification(self):
        """Send template status notification."""
        try:
            status_data = await self.handle_read_template_status()
            await self._send_notification(TEMPLATE_STATUS_UUID, status_data)
        except Exception as e:
            logger.error(f"Error sending status notification: {e}")
    
    async def _send_notification(self, characteristic_uuid: str, data: bytes):
        """Send notification for a characteristic."""
        if self.notify_callback:
            self.notify_callback(characteristic_uuid, data)
    
    # Background Tasks
    
    async def _status_notification_loop(self):
        """Background status notification loop."""
        while True:
            try:
                await asyncio.sleep(self.status_notify_interval)
                
                # Send status update if operation is active
                if (self.current_operation_id and 
                    self.operation_status == TemplateOperationStatus.PROCESSING):
                    await self._send_status_notification()
                
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Status notification loop error: {e}")
    
    # Utility Methods
    
    async def _cancel_current_operation(self, reason: str):
        """Cancel current operation."""
        if self.current_operation_id:
            self.operation_status = TemplateOperationStatus.ERROR
            self.operation_error = f"Cancelled: {reason}"
            self.current_operation_id = None
            
            # Clear sessions
            self.upload_session = None
            self.download_session = None
    
    # Service Interface
    
    def set_notify_callback(self, callback: Callable[[str, bytes], None]):
        """Set notification callback."""
        self.notify_callback = callback
    
    def get_service_definition(self) -> Dict[str, Any]:
        """Get GATT service definition."""
        return self.service_data
    
    def get_template_statistics(self) -> Dict[str, Any]:
        """Get template service statistics."""
        return {
            "template_service": {
                "is_running": self.status_task is not None and not self.status_task.done(),
                "current_operation_id": self.current_operation_id,
                "operation_status": self.operation_status.value,
                "operation_progress": self.operation_progress,
                "upload_active": self.upload_session is not None,
                "download_active": self.download_session is not None,
                "notification_interval": self.status_notify_interval
            }
        }
    
    async def cleanup(self):
        """Clean up service resources."""
        await self.stop()
        
        # Clear state
        self.current_operation_id = None
        self.operation_status = TemplateOperationStatus.IDLE
        self.upload_session = None
        self.download_session = None
        self.operation_result = None
        self.operation_error = None
        
        logger.info("TemplateService cleanup completed")


# Example usage and testing
if __name__ == "__main__":
    import asyncio
    from unittest.mock import MagicMock, AsyncMock
    
    async def test_template_service():
        """Test template service."""
        # Create mock dependencies
        template_manager = MagicMock()
        template_applicator = MagicMock()
        
        # Mock async methods
        template_manager.create_template = AsyncMock(return_value="template_123")
        template_manager.list_templates = AsyncMock(return_value=[])
        template_manager.get_template = AsyncMock(return_value=None)
        
        # Create service
        service = TemplateService(template_manager, template_applicator)
        
        # Set notification callback
        notifications = []
        def notify_callback(uuid, data):
            notifications.append((uuid, data))
        
        service.set_notify_callback(notify_callback)
        
        # Start service
        await service.start()
        
        try:
            # Test service definition
            service_def = service.get_service_definition()
            print(f"Service UUID: {service_def['uuid']}")
            print(f"Characteristics: {len(service_def['characteristics'])}")
            
            # Test template list read
            list_data = await service.handle_read_template_list()
            print(f"Template list data length: {len(list_data)} bytes")
            
            # Test create template command
            create_params = json.dumps({
                "name": "Test Template",
                "description": "Test template description",
                "category": "network",
                "default_values": {"wifi": {"ssid": "TestNet"}}
            }).encode('utf-8')
            
            create_cmd = bytes([TemplateCommand.CREATE_TEMPLATE.value]) + create_params
            success = await service.handle_write_template_control(create_cmd)
            print(f"Create template command: {'success' if success else 'failed'}")
            
            # Wait for command processing
            await asyncio.sleep(2)
            
            # Test status read
            status_data = await service.handle_read_template_status()
            print(f"Status data length: {len(status_data)} bytes")
            
            # Get statistics
            stats = service.get_template_statistics()
            print(f"Service statistics:")
            for key, value in stats["template_service"].items():
                print(f"  {key}: {value}")
            
            print(f"Received {len(notifications)} notifications")
            
        finally:
            await service.cleanup()
    
    # Run test
    asyncio.run(test_template_service())